using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Diagnostics;

namespace System.IO.IsolatedStorage
{
    public static class PSFile
    {
        public static StreamWriter AppendText(string path)
        {
            return new StreamWriter(Open(path, FileMode.Append, FileAccess.Write));
        }

        public static void Copy(string sourceFileName, string destFileName)
        {
            var fixedFilePath = PSDirectory.FixPath(sourceFileName);
            var fixedFilePathDest = PSDirectory.FixPath(destFileName);
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                store.CopyFile(fixedFilePath, fixedFilePathDest);
            }
        }

        public static void Copy(string sourceFileName, string destFileName, bool overwrite)
        {
            var fixedFilePath = PSDirectory.FixPath(sourceFileName);
            var fixedFilePathDest = PSDirectory.FixPath(destFileName);
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                store.CopyFile(fixedFilePath, fixedFilePathDest, overwrite);
            }
        }

        public static FileStream Create(string path)
        {
            return Open(path, FileMode.Create);
        }

        public static FileStream Create(string path, int bufferSize)
        {
            return Create(path);
            //// Can't set buffersize (leaving this alone for compatibility with existing calls to System.IO.File)
            //var fixedFilePath = PSDirectory.FixPath(path);
            //if (!PSFile.Exists(path))
            //    throw new System.IO.IOException("File was found. Can't create it.");

            //return IsolatedStorageFile.GetUserStoreForApplication().CreateFile(fixedFilePath);
        }

        public static StreamWriter CreateText(string path)
        {
            var fixedFilePath = PSDirectory.FixPath(path);
            CheckFileExistenceAgainstFileMode(fixedFilePath, FileMode.CreateNew);

            return new StreamWriter(Create(path));
        }

        public static void Delete(string path)
        {
            var fixedFilePath = PSDirectory.FixPath(path);
            IsolatedStorageFile.GetUserStoreForApplication().DeleteFile(fixedFilePath);
        }

        public static bool Exists(string path)
        {
            var fixedFilePath = PSDirectory.FixPath(path);
            return IsolatedStorageFile.GetUserStoreForApplication().FileExists(fixedFilePath);
        }

        public static DateTime GetCreationTime(string path)
        {
#if !WINDOWS_PHONE
            var fixedFilePath = PSDirectory.FixPath(path);
            return IsolatedStorageFile.GetUserStoreForApplication().GetCreationTime(fixedFilePath).LocalDateTime;
#else
            return DateTime.Now; // Non existent API in WiNdows Phone
#endif
        }

        public static DateTime GetLastAccessTime(string path)
        {
#if !WINDOWS_PHONE
            var fixedFilePath = PSDirectory.FixPath(path);
            return IsolatedStorageFile.GetUserStoreForApplication().GetLastAccessTime(fixedFilePath).LocalDateTime;
#else
            return DateTime.Now; // Non existent API in WiNdows Phone
#endif
        }

        public static DateTime GetLastWriteTime(string path)
        {
#if !WINDOWS_PHONE
            var fixedFilePath = PSDirectory.FixPath(path);
            return IsolatedStorageFile.GetUserStoreForApplication().GetLastWriteTime(fixedFilePath).LocalDateTime;
#else
            return DateTime.Now; // Non existent API in WiNdows Phone
#endif
        }

        public static void Move(string sourceFileName, string destFileName)
        {
            var fixedFilePath = PSDirectory.FixPath(sourceFileName);
            var fixedFilePathDest = PSDirectory.FixPath(destFileName);
            
            if (!PSFile.Exists(sourceFileName))
                throw new FileNotFoundException();

            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                store.MoveFile(fixedFilePath, fixedFilePathDest);
            }
        }

        public static FileStream Open(string path, FileMode mode)
        {
            return Open(path, mode, FileAccess.ReadWrite);
        }

        public static FileStream Open(string path, FileMode mode, FileAccess access)
        {
            return Open(path, mode, access, access == FileAccess.Read ? FileShare.Read : FileShare.None);

            //var fixedFilePath = PSDirectory.FixPath(path);
            //return IsolatedStorageFile.GetUserStoreForApplication().OpenFile(fixedFilePath, mode, access);
        }

        public static FileStream Open(string path, FileMode mode, FileAccess access, FileShare share)
        {
            var fixedFilePath = PSDirectory.FixPath(path);

            CheckFileExistenceAgainstFileMode(path, mode);
            return IsolatedStorageFile.GetUserStoreForApplication().OpenFile(fixedFilePath, mode, access, share);
        }

        private static void CheckFileExistenceAgainstFileMode(string path, FileMode mode)
        {
            if (!PSFile.Exists(path) && FileModeRequiresFileExists(mode))
                throw new FileNotFoundException();
            else if (FileModeRequiresFileDoesNotExist(mode) && PSFile.Exists(path))
                throw new System.IO.IOException("File Must exist for this operation");
        }

        private static bool FileModeRequiresFileExists(FileMode mode)
        {
            return (mode == FileMode.Truncate || mode == FileMode.Open || mode == FileMode.Append);
        }

        private static bool FileModeRequiresFileDoesNotExist(FileMode mode)
        {
            return mode == FileMode.CreateNew;
        }

        public static FileStream OpenRead(string path)
        {
            return Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        }

        public static StreamReader OpenText(string path)
        {
            var fixedFilePath = PSDirectory.FixPath(path);
            CheckFileExistenceAgainstFileMode(path, FileMode.Open);

            return new StreamReader(IsolatedStorageFile.GetUserStoreForApplication().OpenFile(fixedFilePath, FileMode.Open, FileAccess.Read));
        }

        public static FileStream OpenWrite(string path)
        {
            return Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite);
        }

        public static void SetAttributes(string path, FileAttributes fileAttributes)
        {
            // Here for Compatibility
        }

        public static long FileLength(string path)
        {
            try
            {
                using (var stream = Open(path, FileMode.Open, FileAccess.Read, FileShare.None))
                {
                    return stream.Length;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("In {1}.{2} tagged {3}, swallowing Error {0}", ex, "PSFile", "FileLength()", "full");
            }
            return 0;
        }

        public static void WriteAllBytes(string path, byte[] bytes)
        {
            using (var newFile = Open(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None))
            {
                newFile.Write(bytes, 0, bytes.Length);
            }
        }
    }

#if WINDOWS_PHONE

    internal static class IsoStorFileExtensions
    {
        public static void MoveFile(this IsolatedStorageFile store, string sourceFileName, string destFileName)
        {
            store.CopyFile(sourceFileName, destFileName);
            store.DeleteFile(sourceFileName);
        }

        public static void CopyFile(this IsolatedStorageFile store, string sourceFileName, string destFileName)
        {
            store.CopyFile(sourceFileName, destFileName, true);
        }

        internal static void CopyFile(this IsolatedStorageFile store, string sourceFileName, string destFileName, bool overwrite)
        {
            if (!store.FileExists(sourceFileName))
            {
                throw new FileNotFoundException();
            }

            if (overwrite && store.FileExists(destFileName))
            {
                store.DeleteFile(destFileName);
            }

            using (var strmI = store.OpenFile(sourceFileName, FileMode.Open, FileAccess.Read, FileShare.None))
            {
                using (var strmO = store.CreateFile(destFileName))
                {
                    long len = strmI.Length;
                    int bufferSize = 0;
                    if (len < 100 * 1024)
                        bufferSize = (int)len;
                    else
                        bufferSize = 100 * 1024;
                    var buffr = new byte[bufferSize];

                    int bytesRead = 0;
                    while (len > 0)
                    {
                        var bytesToRead = (int)Math.Min(len, bufferSize);
                        bytesRead = strmI.Read(buffr, 0, bytesToRead);
                        strmO.Write(buffr, 0, bytesRead);
                        len = len - bytesRead;
                    }
                }
            }
        }
    }

#endif
    //public class PSFileStream
    //{
    //    private FileStream fs;
    //    public PSFileStream(FileStream fs)
    //    {
    //        this.fs = fs;

    //    }

    //    public bool CanRead
    //    {
    //        get
    //        {
    //            return fs.CanRead;
    //        }
    //    }
    //    public bool CanSeek
    //    {
    //        get
    //        {
    //            return fs.CanSeek;
    //        }
    //    }
    //    public bool CanTimeout
    //    {
    //        get
    //        {
    //            return fs.CanTimeout;
    //        }
    //    }
    //    public bool CanWrite
    //    {
    //        get
    //        {
    //            return fs.CanWrite;
    //        }
    //    }
    //    public void Close()
    //    {
    //        fs.Close();
    //    }
    //    protected void Dispose(bool disposing)
    //    {
    //        fs.Dispose();
    //        //base.Dispose(disposing);
    //    }
    //    public int EndRead(IAsyncResult asyncResult)
    //    {
    //        return fs.EndRead(asyncResult);
    //    }
    //    public void EndWrite(IAsyncResult asyncResult)
    //    {
    //        fs.EndWrite(asyncResult);
    //    }
    //    public bool Equals(object obj)
    //    {
    //        return fs.Equals(obj);
    //    }
    //    public void Flush()
    //    {
    //        fs.Flush();
    //    }
    //    public int GetHashCode()
    //    {
    //        return fs.GetHashCode();
    //    }
    //    public long Length
    //    {
    //        get
    //        {
    //            return fs.Length;
    //        }
    //    }
    //    public long Position
    //    {
    //        get
    //        {
    //            return fs.Position;
    //        }
    //        set
    //        {
    //            fs.Position = value;
    //        }
    //    }
    //    public int Read(byte[] array, int offset, int count)
    //    {
    //        return fs.Read(array, offset, count);
    //    }
    //    public int ReadByte()
    //    {
    //        return fs.ReadByte();
    //    }
    //    public int ReadTimeout
    //    {
    //        get
    //        {
    //            return fs.ReadTimeout;
    //        }
    //        set
    //        {
    //            fs.ReadTimeout = value;
    //        }
    //    }
    //    public long Seek(long offset, SeekOrigin origin)
    //    {
    //        return fs.Seek(offset, origin);
    //    }
    //    public void SetLength(long value)
    //    {
    //        fs.SetLength(value);
    //    }
    //    public string ToString()
    //    {
    //        return fs.ToString();
    //    }
    //    public int WriteTimeout
    //    {
    //        get
    //        {
    //            return fs.WriteTimeout;
    //        }
    //        set
    //        {
    //            fs.WriteTimeout = value;
    //        }
    //    }
    //    public IAsyncResult BeginWrite(byte[] array, int offset, int numBytes, AsyncCallback userCallback, object stateObject)
    //    {
    //        PSDirectory.DoAutoAllocCheck(numBytes > 0 ? numBytes : 0);
    //        return fs.BeginWrite(array, offset, numBytes, userCallback, stateObject);
    //    }
    //    public IAsyncResult BeginRead(byte[] array, int offset, int numBytes, AsyncCallback userCallback, object stateObject)
    //    {
    //        PSDirectory.DoAutoAllocCheck(numBytes > 0 ? numBytes : 0);
    //        return fs.BeginRead(array, offset, numBytes, userCallback, stateObject);
    //    }
    //    public void Write(byte[] array, int offset, int count)
    //    {
    //        PSDirectory.DoAutoAllocCheck(count > 0 ? count : array.Length);
    //        fs.Write(array, offset, count);
    //    }
    //    public void WriteByte(byte value)
    //    {
    //        PSDirectory.DoAutoAllocCheck(1);
    //        fs.WriteByte(value);
    //    }
    //}
}